package com.uuah.server.config.registry;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import com.uuah.exception.lifecycle.InitialisationException;
import com.uuah.server.UuahServer;
import com.uuah.server.api.config.registry.IRegistry;
import com.uuah.server.api.config.registry.IRegistryBroker;
import com.uuah.server.api.context.IUuahContextAware;
import com.uuah.server.exception.registry.RegistrationException;

public abstract class AbstractRegistryBroker implements IRegistryBroker {
	public void initialise() throws InitialisationException {
		addRegistry(-1, new TransientRegistry());

		Iterator it = getRegistries().iterator();
		while (it.hasNext()) {
			((IRegistry) it.next()).initialise();
		}
	}

	public void dispose() {
		Iterator it = getRegistries().iterator();
		while (it.hasNext()) {
			((IRegistry) it.next()).dispose();
		}
	}

	public String getRegistryId() {
		return this.toString();
	}

	public boolean isReadOnly() {
		return false;
	}

	public boolean isRemote() {
		return false;
	}

	abstract protected Collection<IRegistry> getRegistries();

	public Object lookupObject(String key) {
		Object obj = null;
		Iterator it = getRegistries().iterator();
		while (obj == null && it.hasNext()) {
			obj = ((IRegistry) it.next()).lookupObject(key);
		}
		return obj;
	}

	public Object lookupObject(Class type) throws RegistrationException {
		Collection objects = lookupObjects(type);

		if (objects.size() == 1) {
			return objects.iterator().next();
		} else if (objects.size() > 1) {
			throw new RegistrationException("More than one object of type "
					+ type + " registered but only one expected.");
		} else {
			return null;
		}
	}

	public Collection lookupObjects(Class type) {
		Collection objects = new ArrayList();

		Iterator it = getRegistries().iterator();
		while (it.hasNext()) {
			objects.addAll(((IRegistry) it.next()).lookupObjects(type));
		}
		return objects;
	}

	public void registerObject(String key, Object value)
			throws RegistrationException {
		registerObject(key, value, null);
	}

	public void registerObject(String key, Object value, Object metadata)
			throws RegistrationException {
		if (value instanceof IUuahContextAware) {
			((IUuahContextAware) value)
					.setUuahContext(UuahServer.getUuahContext());
		}

		Iterator it = getRegistries().iterator();
		IRegistry reg;
		while (it.hasNext()) {
			reg = (IRegistry) it.next();
			if (!reg.isReadOnly()) {
				reg.registerObject(key, value, metadata);
				break;
			}
		}
	}

	public void registerObjects(Map objects) throws RegistrationException {
		Iterator it = objects.keySet().iterator();
		Object key;
		while (it.hasNext()) {
			key = it.next();
			registerObject((String) key, objects.get(key));
		}
	}

	public void unregisterObject(String key) throws RegistrationException {
		unregisterObject(key, null);
	}

	public void unregisterObject(String key, Object metadata)
			throws RegistrationException {
		Iterator it = getRegistries().iterator();
		IRegistry reg;
		while (it.hasNext()) {
			reg = (IRegistry) it.next();
			if (!reg.isReadOnly() && reg.lookupObject(key) != null) {
				reg.unregisterObject(key, metadata);
				break;
			}
		}
	}
}
